﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using ParsecParser;
using ParsecParser.Communication;
using ParsecParser.Data;
using ParsecParser.Display;
using ParsecParser.Helpers;
using System.IO;
using Microsoft.Win32;
using ParsecClient.Classes;
using System.Diagnostics;
using ParsecClient.ParsecRaidWebService;
using System.Configuration;

namespace ParsecClient
{
    /// <summary>
    /// Interaction logic for ShareFightWindow.xaml
    /// </summary>
    public partial class ShareFightWindow : Window
    {
        public ShareFightWindow()
        {
            InitializeComponent();
            IEnumerable<RaidGroup> source = (new List<RaidGroup>(){new RaidGroup(){Name="None"}}).Union(((App)Application.Current).RaidGroups);
            
            ddlGroups.ItemsSource = source;
            ddlGroups.SelectedValuePath = "Name";
            ddlGroups.DisplayMemberPath = "Name"; 
        }
        public CombatDetails CurrentFight { get; set; }
        //private void ShareFight()
        //{
        //    //CombatDetails cloneFight = CurrentFight.Serialize().Deserialize<CombatDetails>();
        //    //cloneFight.Events.ForEach(x => x.RawString = null);
        //    //cloneFight.RaidDetails.Clear();
        //    RaidGroup rg = null;
        //    if (ddlGroups.SelectedValue != null && (string)ddlGroups.SelectedValue != "None")
        //    {
        //        rg = ((App)Application.Current).RaidGroups.FirstOrDefault(x => string.Compare(x.Name, (string)ddlGroups.SelectedValue, true) == 0);
        //    }
        //    ArchiveFightRequest afr = new ArchiveFightRequest()
        //    {
        //        UserName = "dcerny",
        //        Password = "MyPass",
        //        RaidGroup = rg != null ? rg.Name : null,
        //        RaidGroupPassword = rg != null ? rg.Password : null,
        //        CharacterName = CurrentFight.CharacterName,
        //        //Fight = cloneFight
        //        FightLog = string.Join(Environment.NewLine, CurrentFight.Events.Select(x=>x.RawString).ToArray()),
        //        GuardCount = CurrentFight.LogStateAtStart.GuardCount,
        //        OverrideRaidEncounterMode = ddlDifficulty.Visibility == System.Windows.Visibility.Visible ? Convert.ToInt32(((ComboBoxItem)ddlDifficulty.SelectedValue).Tag) : (int?)null,
        //        OverrideRaidEncounterPlayers = ddlPlayerMode.Visibility == System.Windows.Visibility.Visible ? Convert.ToInt32(((ComboBoxItem)ddlPlayerMode.SelectedValue).Tag) : (int?)null
        //    };
        //    string compressed = afr.SerializeAndCompress();
        //    //int size = System.Text.ASCIIEncoding.Default.GetByteCount(compressed);
        //    string encrypted = AESThenHMAC.SimpleEncryptWithPassword(compressed, "ThisIsMyPassword");
        //    //string decrypted = AESThenHMAC.SimpleDecryptWithPassword(encrypted, "ThisIsMyPassword");
        //    //ArchiveFightRequest decompressed = decrypted.DecompressAndDeserialize<ArchiveFightRequest>();
        //    //CombatDetails fight = decompressed.GetFight();

        //    var rval = ((ParsecWindow)Application.Current.MainWindow).RaidService.UploadLog(encrypted);
        //    if (!string.IsNullOrEmpty(rval.ErrorMessage))
        //    {
        //        ((App)Application.Current).HandleError("Error Uploading Log: " + rval.ErrorMessage, "Error from Service:" + rval.ErrorMessage, null, true, this);
        //    }
        //    else
        //    {
        //        ((App)Application.Current).HandleMessage("Uploaded:" + CurrentFight.CharacterName + " " + CurrentFight.RaidEncounterDetail.ToString() + string.Format(" (Id: {0})", rval.UploadId), this);
        //    }


        //    //CombatDetails currentFight = new CombatDetails();
        //    //int newSelectedFightIndex = Convert.ToInt32(ddlFights.SelectedValue);
        //    //if (newSelectedFightIndex > 0)
        //    //{
        //    //    currentFight = Log.Fights[newSelectedFightIndex];
        //    //    CombatDetails cloneFight = currentFight.Serialize().Deserialize<CombatDetails>();
        //    //    cloneFight.Events.ForEach(x => x.RawString = null);
        //    //    cloneFight.RaidDetails.Clear();
        //    //    ArchiveFightRequest afr = new ArchiveFightRequest()
        //    //    {
        //    //        UserName = "dcerny",
        //    //        Password = "MyPass",
        //    //        RaidGroup = null,
        //    //        RaidGroupPassword = null,
        //    //        Fight = cloneFight
        //    //    };
        //    //    string compressed = afr.SerializeAndCompress();
        //    //    string encrypted = AESThenHMAC.SimpleEncryptWithPassword(compressed, "ThisIsMyPassword");
        //    //    //string decrypted = AESThenHMAC.SimpleDecryptWithPassword(encrypted, "ThisIsMyPassword");
        //    //    //ArchiveFightRequest decompressed = decrypted.DecompressAndDeserialize<ArchiveFightRequest>();

        //    //    var rval = ((ParsecWindow)Application.Current.MainWindow).RaidService.UploadLog(encrypted);
        //    //    if (!string.IsNullOrEmpty(rval.ErrorMessage))
        //    //    {
        //    //        ((App)Application.Current).HandleError("Error Uploading Log", rval.ErrorMessage, null, true);
        //    //    }
        //    //    else
        //    //    {
        //    //        ((App)Application.Current).HandleMessage("Uploaded:" + currentFight.CharacterName + " " + currentFight.RaidEncounterDetail.ToString() + string.Format(" (Id: {0})", rval.UploadId), null);
        //    //    }
        //    //}
        //}
        private void btnCancel_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                this.Close();
            }
            catch (Exception ex)
            {
                ((App)Application.Current).HandleError("Error Canceling Settings", "Error on btnCancel_Click", ex, this, true);
                this.Close();
            }
        }

        private void btnShare_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                string username = null;
                string password = null;
                if (string.IsNullOrEmpty(txtUserName.Text) || txtUserName.Text.Contains(" "))
                {
                    UploadProgress.Visibility = System.Windows.Visibility.Hidden;
                    ((App)Application.Current).HandleError("Invalid User Name", null, null, this, false);
                }
                else if (string.IsNullOrEmpty(txtPassword.Password) || txtPassword.Password.Contains(" "))
                {
                    UploadProgress.Visibility = System.Windows.Visibility.Hidden;
                    ((App)Application.Current).HandleError("Invalid Password", null, null, this, false);
                }
                else
                {
                    RaidGroup rg = null;
                    if (ddlGroups.SelectedValue != null && (string)ddlGroups.SelectedValue != "None")
                    {
                        rg = ((App)Application.Current).RaidGroups.FirstOrDefault(x => string.Compare(x.Name, (string)ddlGroups.SelectedValue, true) == 0);
                        if (rg == null)
                        {
                            UploadProgress.Visibility = System.Windows.Visibility.Hidden;
                            ((App)Application.Current).HandleError("Invalid Raid Group", null, null, this, false);
                        }
                    }

                    using (BackgroundWorker worker = new BackgroundWorker())
                    {
                        worker.DoWork += ShareFightWorker;
                        worker.WorkerReportsProgress = true;
                        worker.WorkerSupportsCancellation = false;
                        worker.RunWorkerCompleted += ShareFightCompleted;
                        worker.ProgressChanged += ShareFightProgressChanged;
                        UploadProgress.Value = 0;
                        UploadProgress.Visibility = System.Windows.Visibility.Visible;
                        btnCancel.IsEnabled = false;
                        btnShare.IsEnabled = false;
                        worker.RunWorkerAsync(new ShareFightWorkerArgs()
                            {
                                UserName = username,
                                Password = password,
                                OverrideDifficulty = ddlDifficulty.Visibility == System.Windows.Visibility.Visible ? Convert.ToInt32(((ComboBoxItem)ddlDifficulty.SelectedValue).Tag) : (int?)null,
                                OverridePlayers = ddlPlayerMode.Visibility == System.Windows.Visibility.Visible ? Convert.ToInt32(((ComboBoxItem)ddlPlayerMode.SelectedValue).Tag) : (int?)null,
                                rg = rg,
                                CurrentFight = CurrentFight
                            });
                    }

                }
            }
            catch (Exception ex)
            {
                ((App)Application.Current).HandleError("Error Sharing Log", "Error on btnShare_Click", ex, this, true);
                this.Close();
            }
        }
        private void ShareFightProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            UploadProgress.Value = e.ProgressPercentage;
        }
        private void ShareFightWorker(object sender, DoWorkEventArgs e)
        {
            using (BackgroundWorker worker = sender as BackgroundWorker)
            {
                ShareFightWorkerArgs args = (ShareFightWorkerArgs)e.Argument;
                string[] a = args.CurrentFight.GetEvents().Select(x => x.RawString).ToArray();
                ArchiveFightRequest afr = new ArchiveFightRequest()
                {
                    UserName = args.UserName,
                    Password = args.Password,
                    RaidGroup = args.rg != null ? args.rg.Name : null,
                    RaidGroupPassword = args.rg != null ? args.rg.Password : null,
                    CharacterName = args.CurrentFight.CharacterName,
                    FightLog = string.Join(Environment.NewLine, a),
                    GuardCount = args.CurrentFight.LogStateAtStart.GuardCount,
                    OverrideRaidEncounterMode = args.OverrideDifficulty,
                    OverrideRaidEncounterPlayers = args.OverridePlayers
                };
                worker.ReportProgress(20);
                string compressed = afr.SerializeAndCompress(false);
                worker.ReportProgress(40);
                string encrypted = AESThenHMAC.SimpleEncryptWithPassword(compressed, App.EncryptionKey);
                worker.ReportProgress(60);
                using (ParsecRaidServiceSoapClient rs = new ParsecRaidServiceSoapClient())
                {
                    ParsecUploadResponse rval = rs.UploadLog(encrypted);
                    worker.ReportProgress(90);
                    e.Result = rval;
                }
            }
        }
        private void ShareFightCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            try
            {
                if (e.Error != null)
                {
                    string errorTemplate = "Error Uploading Log: {0}";
                    UploadProgress.Visibility = System.Windows.Visibility.Hidden;
                    ((App)Application.Current).HandleError(string.Format(errorTemplate, e.Error.Message), string.Format(errorTemplate, e.Error.Message), e.Error, this, true);
                    UploadProgress.Visibility = System.Windows.Visibility.Hidden;
                    btnCancel.IsEnabled = true;
                    btnShare.IsEnabled = true;
                }
                else
                {
                    ParsecUploadResponse rval = (ParsecUploadResponse)e.Result;
                    if (!string.IsNullOrEmpty(rval.ErrorMessage))
                    {
                        string errorTemplate = "The server rejected the upload with the message: {0} ({1})";
                        string logTemplate = "Server Error Code: {1} Server Error Message: {0}";

                        switch (rval.ErrorCode)
                        {
                            case "1001":
                                errorTemplate = "Your User Name or Password was not accepted. Please visit the ParsecParser.com website if you need to signup or forgot your password";
                                break;
                            case "1002":
                                errorTemplate = "You have exceeded your upload quota. Please visit the ParsecParser.com website to remove old fights before uploading new ones.";
                                break;
                            case "1003":
                                errorTemplate = "You have exceeded your upload quota. Please visit the ParsecParser.com website to remove old fights before uploading new ones.";
                                break;
                            case "1004":
                                errorTemplate = "Your Raid Group was not found. You can upload the fight without associating it to a Raid Group.";
                                break;
                            case "1005":
                                errorTemplate = "Your Raid Group password was not accepted. You can upload the fight without associating it to a Raid Group or you can use the manage raid groups window to remove and re-add this raid group.";
                                break;
                            case "1010":
                                errorTemplate = "The server rejected the upload because the log data was invalid or corrupt";
                                break;
                            default:
                                break;
                        }

                        string userErrorMessage = string.Format(errorTemplate, rval.ErrorMessage, rval.ErrorCode);
                        string logErrorMessage = string.Format(logTemplate, rval.ErrorMessage, rval.ErrorCode);
                        UploadProgress.Visibility = System.Windows.Visibility.Hidden;
                        btnCancel.IsEnabled = true;
                        btnShare.IsEnabled = true;
                        ((App)Application.Current).HandleError(userErrorMessage, logErrorMessage, null, this, true);
                    }
                    else
                    {
                        UploadProgress.Value = 100;
                        var s = new ShareFightSuccess();
                        s.Owner = this;
                        s.LinkFightId = rval.UploadId;
                        s.ShowDialog();
                        this.Close();
                    }
                }
            }
            catch (Exception ex)
            {
                ((App)Application.Current).HandleError("Error Completing Upload", "Error on ShareFightCompleted", ex, this, true);
                this.Close();
            }
        }
        private void SignUpHandler(object sender, System.Windows.Navigation.RequestNavigateEventArgs e)
        {
            try
            {
                Process.Start(new ProcessStartInfo(App.ParsecSignUpUrl));
                e.Handled = true;
            }
            catch (Exception ex)
            {
                ((App)Application.Current).HandleError("Error Loading Website", "Error on SignUpHandler", ex, this, true);
                this.Close();
            }
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            try
            {
                if (CurrentFight == null)
                {
                    this.Close();
                    ((App)Application.Current).HandleError("No Fight Selected", null, null, null, false);
                }
                else if (CurrentFight.RaidEncounterDetail.RaidEncounterId == 0)
                {
                    this.Close();
                    ((App)Application.Current).HandleError("This Fight does not meet the criteria for sharing: Unrecognized Raid Encounter", null, null, null, false);
                }
                else
                {
                    string password = string.IsNullOrEmpty(ParsecClient.Properties.Settings.Default.ParsecPassword) ? null : AESThenHMAC.SimpleDecryptWithPassword(ParsecClient.Properties.Settings.Default.ParsecPassword, App.EncryptionKey);
                    string username = ParsecClient.Properties.Settings.Default.ParsecUserName;
                    if (!string.IsNullOrEmpty(password) && !string.IsNullOrEmpty(username))
                    {
                        chkSaveIt.IsChecked = true;
                        txtPassword.Password = password;
                        txtUserName.Text = username;
                    }
                    //bind the fight
                    lblCharacterName.Text = CurrentFight.CharacterName;
                    lblEncounterName.Text = CurrentFight.RaidEncounterDetail.ToString();
                    lblDifficulty.Visibility = System.Windows.Visibility.Collapsed;
                    lblPlayers.Visibility = System.Windows.Visibility.Collapsed;
                    ddlPlayerMode.Visibility = System.Windows.Visibility.Collapsed;
                    ddlDifficulty.Visibility = System.Windows.Visibility.Collapsed;
                    if (CurrentFight.RaidEncounterDetail.RaidEncounterId != CombatLogHelpers.GetRaidEncounterDetails(new CombatLogParticipant("", CombatLogConstants.RaidEncounters.OperationsTrainingDummy, 0, false)).RaidEncounterId)
                    {
                        if (CurrentFight.RaidEncounterDetail.Mode == RaidEncounterDetails.DifficultyMode.Unknown)
                        {
                            lblDifficulty.Visibility = System.Windows.Visibility.Visible;
                            ddlDifficulty.Visibility = System.Windows.Visibility.Visible;
                        }
                        if (CurrentFight.RaidEncounterDetail.Players == RaidEncounterDetails.PlayerCount.Unknown)
                        {
                            lblPlayers.Visibility = System.Windows.Visibility.Visible;
                            ddlPlayerMode.Visibility = System.Windows.Visibility.Visible;
                        }
                    }
                    if (!string.IsNullOrEmpty(CurrentFight.RaidGroupName))
                        ddlGroups.SelectedValue = CurrentFight.RaidGroupName;
                    else
                        ddlGroups.SelectedValue = "None";
                    lblLength.Text = String.Format("{0:hh\\:mm\\:ss\\.fff}", CurrentFight.CombatTimeSpan);
                    lblDmgDealt.Text = CurrentFight.DamageOut.ToString("N0") + "   " + (CurrentFight.DamageOut / CurrentFight.CombatTimeSpan.TotalSeconds).ToString("N0");
                    lblHealDone.Text = CurrentFight.HealOut.ToString("N0") + "   " + (CurrentFight.HealOut / CurrentFight.CombatTimeSpan.TotalSeconds).ToString("N0");
                    lblDmgTaken.Text = CurrentFight.DamageIn.ToString("N0") + "   " + (CurrentFight.DamageIn / CurrentFight.CombatTimeSpan.TotalSeconds).ToString("N0");
                }
            }
            catch (Exception ex)
            {
                ((App)Application.Current).HandleError("Error Loading Fight to Share", "Error on ShareFightWindow.Window_Loaded", ex, this, true);
                this.Close();
            }
        }

        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            try
            {
                //save password data
                if (!(chkSaveIt.IsChecked ?? false))
                {
                    ParsecClient.Properties.Settings.Default.ParsecPassword = null;
                    ParsecClient.Properties.Settings.Default.ParsecUserName = null;
                }
                else
                {
                    ParsecClient.Properties.Settings.Default.ParsecPassword = AESThenHMAC.SimpleEncryptWithPassword(txtPassword.Password, App.EncryptionKey);
                    ParsecClient.Properties.Settings.Default.ParsecUserName = txtUserName.Text;
                }
                ParsecClient.Properties.Settings.Default.Save();
            }
            catch (Exception ex)
            {
                ((App)Application.Current).HandleError("Error Saving Username and Password", "Error on ShareFightWindow.Window_Closing", ex, this, true);
                this.Close();
            }
        }
    }
    public class ShareFightWorkerArgs
    {
        public string UserName { get; set; }
        public string Password { get; set; }
        public RaidGroup rg { get; set; }
        public int? OverrideDifficulty { get; set; }
        public int? OverridePlayers { get; set; }
        public CombatDetails CurrentFight { get; set; }
    }
}
